Skip to content

Conversation

@evelez7
Copy link
Member

@evelez7 evelez7 commented Jul 18, 2025

Comment categories will allow better comment organization in HTML.
Before, comments would just be serialized in whatever order they were
written, so groups like params or notes wouldn't be in the same
sections.

Copy link
Member Author

evelez7 commented Jul 18, 2025

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@evelez7 evelez7 marked this pull request as ready for review July 18, 2025 19:07
@llvmbot
Copy link
Member

llvmbot commented Jul 18, 2025

@llvm/pr-subscribers-clang-tools-extra

Author: Erick Velez (evelez7)

Changes

Comment categories will allow better comment organization in HTML.
Before, comments would just be serialized in whatever order they were
written, so groups like params or notes wouldn't be in the same
sections.


Full diff: https://github.com/llvm/llvm-project/pull/149564.diff

3 Files Affected:

  • (modified) clang-tools-extra/clang-doc/JSONGenerator.cpp (+32-9)
  • (modified) clang-tools-extra/test/clang-doc/json/class.cpp (+24-27)
  • (modified) clang-tools-extra/test/clang-doc/json/concept.cpp (+6-9)
diff --git a/clang-tools-extra/clang-doc/JSONGenerator.cpp b/clang-tools-extra/clang-doc/JSONGenerator.cpp
index 908e23d24d079..5c2cb1c75cfee 100644
--- a/clang-tools-extra/clang-doc/JSONGenerator.cpp
+++ b/clang-tools-extra/clang-doc/JSONGenerator.cpp
@@ -83,7 +83,20 @@ serializeLocation(const Location &Loc,
   return LocationObj;
 }
 
-static json::Value serializeComment(const CommentInfo &I) {
+static void insertComment(Object &Description, json::Value &Comment, std::string Key) {
+  auto *CommentArray = Description.getArray(Key);
+  if (!CommentArray) {
+    auto CommentsArray= json::Array();
+    CommentsArray.push_back(Comment);
+    Description[Key] = std::move(CommentsArray);
+    Description["Has" + Key] = true;
+  } else {
+    CommentArray->push_back(Comment);
+    Description[Key] = std::move(*CommentArray);
+  }
+}
+
+static Object serializeComment(const CommentInfo &I, Object &Description) {
   // taken from PR #142273
   Object Obj = Object();
 
@@ -94,7 +107,7 @@ static json::Value serializeComment(const CommentInfo &I) {
   auto &CARef = *ChildArr.getAsArray();
   CARef.reserve(I.Children.size());
   for (const auto &C : I.Children)
-    CARef.emplace_back(serializeComment(*C));
+    CARef.emplace_back(serializeComment(*C, Description));
 
   switch (I.Kind) {
   case CommentKind::CK_TextComment: {
@@ -106,6 +119,8 @@ static json::Value serializeComment(const CommentInfo &I) {
     Child.insert({"Command", I.Name});
     Child.insert({"Children", ChildArr});
     Obj.insert({commentKindToString(I.Kind), ChildVal});
+    if (I.Name == "brief")
+      insertComment(Description, ChildVal, "BriefComments");
     return Obj;
   }
 
@@ -137,7 +152,10 @@ static json::Value serializeComment(const CommentInfo &I) {
     if (!I.CloseName.empty())
       Child.insert({"CloseName", I.CloseName});
     Child.insert({"Children", ChildArr});
-    Obj.insert({commentKindToString(I.Kind), ChildVal});
+    if (I.CloseName == "endcode")
+      insertComment(Description, ChildVal, "CodeComments");
+    else if (I.CloseName == "endverbatim")
+      insertComment(Description, ChildVal, "VerbatimComments");
     return Obj;
   }
 
@@ -210,12 +228,17 @@ serializeCommonAttributes(const Info &I, json::Object &Obj,
   }
 
   if (!I.Description.empty()) {
-    json::Value DescArray = json::Array();
-    auto &DescArrayRef = *DescArray.getAsArray();
-    DescArrayRef.reserve(I.Description.size());
-    for (const auto &Comment : I.Description)
-      DescArrayRef.push_back(serializeComment(Comment));
-    Obj["Description"] = DescArray;
+    Object Description = Object();
+    // Skip straight to the FullComment's children
+    auto &Comments = I.Description.at(0).Children;
+    for (const auto &CommentInfo: Comments)
+    {
+      json::Value Comment = serializeComment(*CommentInfo, Description);
+      // Paragraph comments might not be children
+      if (auto *ParagraphComment = Comment.getAsObject()->get("ParagraphComment"))
+        insertComment(Description, *ParagraphComment, "ParagraphComments");
+    }
+    Obj["Description"] = std::move(Description);
   }
 
   // Namespaces aren't SymbolInfos, so they dont have a DefLoc
diff --git a/clang-tools-extra/test/clang-doc/json/class.cpp b/clang-tools-extra/test/clang-doc/json/class.cpp
index a36358982b019..e8fafca28a956 100644
--- a/clang-tools-extra/test/clang-doc/json/class.cpp
+++ b/clang-tools-extra/test/clang-doc/json/class.cpp
@@ -33,33 +33,30 @@ struct MyClass {
 };
 
 // CHECK:       {
-// CHECK-NEXT:    "Description": [
-// CHECK-NEXT:      {
-// CHECK-NEXT:       "FullComment": {
-// CHECK-NEXT:         "Children": [
-// CHECK-NEXT:           {
-// CHECK-NEXT:             "ParagraphComment": {
-// CHECK-NEXT:               "Children": [
-// CHECK-NEXT:                 {
-// CHECK-NEXT:                   "TextComment": " This is a nice class."
-// CHECK-NEXT:                 },
-// CHECK-NEXT:                 {
-// CHECK-NEXT:                   "TextComment": " It has some nice methods and fields."
-// CHECK-NEXT:                 },
-// CHECK-NEXT:                 {
-// CHECK-NEXT:                   "TextComment": ""
-// CHECK-NEXT:                 }
-// CHECK-NEXT:               ]
-// CHECK:               {
-// CHECK-NEXT:             "BlockCommandComment": {
-// CHECK-NEXT:               "Children": [
-// CHECK-NEXT:                 {
-// CHECK-NEXT:                   "ParagraphComment": {
-// CHECK-NEXT:                     "Children": [
-// CHECK-NEXT:                       { 
-// CHECK-NEXT:                         "TextComment": " This is a brief description." 
-// CHECK-NEXT:                       }
-// CHECK:                   "Command": "brief"
+// CHECK-NEXT:    "Description": {
+// CHECK-NEXT:      "BriefComments": [
+// CHECK-NEXT:        {
+// CHECK-NEXT:          "Children": [
+// CHECK-NEXT:            {
+// CHECK-NEXT:              "ParagraphComment": {
+// CHECK-NEXT:                "Children": [
+// CHECK-NEXT:                  {
+// CHECK-NEXT:                    "TextComment": " This is a brief description."
+// CHECK:               "Command": "brief"
+// CHECK:           "HasBriefComments": true,
+// CHECK-NEXT:      "HasParagraphComments": true,
+// CHECK-NEXT:      "ParagraphComments": [
+// CHECK-NEXT:        {
+// CHECK-NEXT:          "Children": [
+// CHECK-NEXT:            {
+// CHECK-NEXT:              "TextComment": " This is a nice class."
+// CHECK-NEXT:            },
+// CHECK-NEXT:            {
+// CHECK-NEXT:              "TextComment": " It has some nice methods and fields."
+// CHECK-NEXT:            },
+// CHECK-NEXT:            {
+// CHECK-NEXT:              "TextComment": ""
+// CHECK-NEXT:            }
 // CHECK:         "DocumentationFileName": "_ZTV7MyClass",
 // CHECK:         "Enums": [
 // CHECK-NEXT:      {
diff --git a/clang-tools-extra/test/clang-doc/json/concept.cpp b/clang-tools-extra/test/clang-doc/json/concept.cpp
index 766415bbbeecd..2874caf28f8f5 100644
--- a/clang-tools-extra/test/clang-doc/json/concept.cpp
+++ b/clang-tools-extra/test/clang-doc/json/concept.cpp
@@ -13,16 +13,13 @@ concept Incrementable = requires(T x) {
 // CHECK-NEXT:    "Concepts": [
 // CHECK-NEXT:      {
 // CHECK-NEXT:        "ConstraintExpression": "requires (T x) { ++x; x++; }",
-// CHECK-NEXT:        "Description": [
+// CHECK-NEXT:        "Description": {
+// CHECK-NEXT:        "HasParagraphComments": true,
+// CHECK-NEXT:        "ParagraphComments": [
 // CHECK-NEXT:          {
-// CHECK-NEXT:            "FullComment": {
-// CHECK-NEXT:              "Children": [
-// CHECK-NEXT:                {
-// CHECK-NEXT:                  "ParagraphComment": {
-// CHECK-NEXT:                    "Children": [
-// CHECK-NEXT:                      {
-// CHECK-NEXT:                        "TextComment": " Requires that T suports post and pre-incrementing."
-// CHECK:             ],
+// CHECK-NEXT:            "Children": [
+// CHECK-NEXT:              {
+// CHECK-NEXT:                "TextComment": " Requires that T suports post and pre-incrementing."
 // CHECK:             "End": true,
 // CHECK-NEXT:        "InfoType": "concept",
 // CHECK-NEXT:        "IsType": true,

@github-actions
Copy link

github-actions bot commented Jul 18, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

Comment categories will allow better comment organization in HTML.
Before, comments would just be serialized in whatever order they were
written, so groups like params or notes wouldn't be in the same
sections.
@evelez7 evelez7 force-pushed the users/evelez7/clang-doc-revamp-comments branch from 959b078 to 0e6eaa3 Compare July 18, 2025 19:13
@evelez7 evelez7 requested review from ilovepi and petrhosek July 18, 2025 19:47
Copy link
Contributor

@ilovepi ilovepi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems mostly fine. I'll probably LGTM once I go through the whole stack.

Comment on lines +237 to +240
// Paragraph comments might not be children
if (auto *ParagraphComment =
Comment.getAsObject()->get("ParagraphComment"))
insertComment(Description, *ParagraphComment, "ParagraphComments");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment here implies to me that we may be missing paragraph comments. Am I understanding that correctly?

Copy link
Member Author

@evelez7 evelez7 Jul 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, because all paragraph comments were previously handled.

This is meant to signal that there are top level ParagraphComments that can be returned from serializeComment that need to be manually inserted into Description with this modified scheme. They can't be added like brief comments now are because we can't be sure if the ParagraphComment is nested (the text of a brief command is a paragraph comment). So, if the returned comment is a ParagraphComment, then it must be a top-level, standalone comment without a command.

Maybe this comment could use a revision. I just wanted to clarify why the ParagraphComment is handled specially here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, rewording would be helpful. thanks

@evelez7 evelez7 closed this Jul 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants